logo
menu

useQuery 구현하기 1탄 | 커스텀 useFetch 구현

2023. 10. 08.

  • #리액트

react-query 를 잘 이용하고 있다. 하지만 가끔씩 순수 react 로만 기능을 구현할 때 react-query 의 useQuery 패턴으로 api 상태(서버 상태)를 관리하는게 더 좋다고 생각되어 해당 기능을 구현한 경험을 공유하고자 한다. 해당 편은 1탄으로 useFetch 로 loading, error, data 를 관리하는 커스텀 훅을 구현한 내용을 공유한다 2탄은 useQuery 를 직접 구현하고 캐시 및 Suspense 까지 적용한 과정을 공유한다. 3탄은 간단한 useInfiniteQuery 및 errorBoundary 를 구현한 내용을 공유한다.
 

UI 내용

실제로 동작하는 것을 기준으로 설명하는 것을 선호하고 더 이해하기 싶다고 생각해서 아주 간단한 프로젝트로 설명하고자 한다.
notion image

구현하기

💡
자세한 코드는 여기를 참고

useFetch custom hook

// hooks/useFetch.ts import { useEffect, useState } from 'react'; export function useFetch<T>(fetcher: () => Promise<T>) { const [isLoading, setIsLoading] = useState<boolean>(false); const [data, setData] = useState<T | undefined>(undefined); const [error, setError] = useState<Error | null>(null); useEffect(() => { async function fetchData() { setIsLoading(true); try { const response = await fetcher(); setData(response); setError(null); } catch (err) { if (err instanceof Error) { setError(err); } setData(undefined); } finally { setIsLoading(false); } } fetchData(); }, [fetcher]); return { isLoading, data, error }; }
  • API 를 요청하면 로딩 유무 및 응답 데이터 또는 에러를 일반적으로 많이 사용한다고 생각하여
    • API 요청시 로딩중, 응답 성공시 데이터, 에러가 발생하면 에러 를 나타내는 커스텀훅이다
 

useFetch 핵심 로직 설명

useEffect(() => { async function fetchData() { setIsLoading(true); try { const response = await fetcher(); setData(response); setError(null); } catch (err) { if (err instanceof Error) { setError(err); } setData(undefined); } finally { setIsLoading(false); } } fetchData(); }, [fetcher]);
  • 우선 해당 API 가 요청되면 isLoading 을 true로 전환하고 해당 API 가 끝난 경우(finally 구문) isLoading 을 false 로 변환한다.
  • 만약 응답이 성공하는 경우(try 구문)
    • 해당 응답값을 setData 를 통해 data 상태를 변환하고 setError 를 null 로 변환한다.
      왜냐하면 이전에 요청할 때 error 인 경우 error 정보가 있을 수 있기 때문이다. (이번 요청은 성공했기에 error 를 초기화 한다고 생각하면 된다)
  • 응답이 실패한 경우 (catch 구문)
    • error 값을 error 상태로 변환하고 기존에 data 를 초기화한다.
      위와 마찬가지로 이번 요청은 실패했기에 data 가 없는 경우이기 때문이다.

참고